﻿using IAutoMapper = AutoMapper.IMapper;
using IAutoMapperGlobalConfiguration = AutoMapper.Internal.IGlobalConfiguration;
using IMapper = MicroCloud.Mapping.IMapper;

namespace MicroCloud.AutoMapper
{
    #region "AutoMapper映射执行类"
    /// <summary>
    /// AutoMapper映射执行类
    /// </summary>
    public class AutoMapperMapper : IMapper
    {
        //字段
        private readonly IAutoMapperGlobalConfiguration _configuration;
        //private readonly global::AutoMapper.IMapper _mapper;
        private readonly IAutoMapper _mapper;

        #region "构造函数"
        #region "初始化一个AutoMapper映射执行类的新实例"
        /// <summary>
        /// 初始化一个AutoMapper映射执行类 <see cref="AutoMapperMapper"/> 的新实例
        /// </summary>
        /// <param name="configuration"></param>
        public AutoMapperMapper(IAutoMapperGlobalConfiguration configuration)
        {
            _configuration = configuration;
            _mapper = configuration.CreateMapper();
        }
        #endregion

        #endregion

        #region "方法"
        #region "将对象映射为指定类型"
        /// <summary>
        /// 将对象映射为指定类型
        /// </summary>
        /// <typeparam name="TTarget">要映射的目标类型</typeparam>
        /// <param name="source">源对象</param>
        /// <returns>目标类型的对象</returns>
        public TTarget MapTo<TTarget>(object source)
        {
            var sourceType = source.GetType();
            var targetType = typeof(TTarget);
            if (_configuration.FindTypeMapFor(sourceType, targetType) != null)
            {
                return _mapper.Map<TTarget>(source);
            }
            var config = new MapperConfiguration(cfg => cfg.CreateMap(sourceType, targetType));
            var mapper = config.CreateMapper();
            return mapper.Map<TTarget>(source);
        }
        #endregion
        #region "将对象映射为指定类型"
        /// <summary>
        /// 将对象映射为指定类型
        /// </summary>
        /// <typeparam name="TSource">源类型</typeparam>
        /// <typeparam name="TTarget">目标类型</typeparam>
        /// <param name="source">源对象</param>
        /// <returns>目标类型的对象</returns>
        public TTarget MapTo<TSource, TTarget>(TSource source)
        {
            if (_configuration.FindTypeMapFor<TSource, TTarget>() != null)
            {
                return _mapper.Map<TSource, TTarget>(source);
            }
            var config = new MapperConfiguration(cfg => cfg.CreateMap<TSource, TTarget>());
            var mapper = config.CreateMapper();
            return mapper.Map<TSource, TTarget>(source);
        }
        #endregion
        #region "使用源类型的对象更新目标类型的对象"
        /// <summary>
        /// 使用源类型的对象更新目标类型的对象
        /// </summary>
        /// <typeparam name="TSource">源类型</typeparam>
        /// <typeparam name="TTarget">目标类型</typeparam>
        /// <param name="source">源对象</param>
        /// <param name="target">待更新的目标对象</param>
        /// <returns>更新后的目标类型对象</returns>
        public TTarget MapTo<TSource, TTarget>(TSource source, TTarget target)
        {
            if (_configuration.FindTypeMapFor<TSource, TTarget>() != null)
            {
                return _mapper.Map(source, target);
            }
            var config = new MapperConfiguration(cfg => cfg.CreateMap<TSource, TTarget>());
            var mapper = config.CreateMapper();
            return mapper.Map(source, target);
        }
        #endregion
        #region "将数据源映射为指定输出DTO的集合"
        /// <summary>
        /// 将数据源映射为指定输出DTO的集合
        /// </summary>
        /// <typeparam name="TOutputDto">输出DTO类型</typeparam>
        /// <param name="source">数据源</param>
        /// <param name="membersToExpand">成员展开</param>
        /// <returns>输出DTO的结果集</returns>
        public IQueryable<TOutputDto> ToOutput<TOutputDto>(IQueryable source, params Expression<Func<TOutputDto, object>>[] membersToExpand)
        {
            return source.ProjectTo(_configuration, membersToExpand);
        }
        #endregion

        #region "将对象映射为指定类型的集合"
        /// <summary>
        /// 将对象映射为指定类型的集合
        /// </summary>
        /// <typeparam name="TSource">源类型</typeparam>
        /// <typeparam name="TTarget">目标类型</typeparam>
        /// <param name="source">源对象集合</param>
        /// <returns>目标类型对象集合</returns>
        public IEnumerable<TTarget> MapToList<TSource, TTarget>(IEnumerable<TSource> source)
        {
            if (_configuration.FindTypeMapFor<TSource, TTarget>() != null)
            {
                return _mapper.Map<IEnumerable<TTarget>>(source);
            }
            var config = new MapperConfiguration(cfg => cfg.CreateMap<TSource, TTarget>());
            var mapper = config.CreateMapper();
            return mapper.Map<IEnumerable<TTarget>>(source);
        }
        #endregion
        #region "使用源类型的对象集合更新目标类型的对象集合"
        /// <summary>
        /// 使用源类型的对象集合更新目标类型的对象集合
        /// </summary>
        /// <typeparam name="TSource">源类型</typeparam>
        /// <typeparam name="TTarget">目标类型</typeparam>
        /// <param name="source">源对象集合</param>
        /// <param name="target">待更新的目标对象集合</param>
        /// <returns>更新后的目标类型对象集合</returns>
        public IEnumerable<TTarget> MapToList<TSource, TTarget>(IEnumerable<TSource> source, IEnumerable<TTarget> target)
        {
            if (_configuration.FindTypeMapFor<TSource, TTarget>() != null)
            {
                return _mapper.Map(source, target);
            }
            var config = new MapperConfiguration(cfg => cfg.CreateMap<TSource, TTarget>());
            var mapper = config.CreateMapper();
            return mapper.Map(source, target);
        }
        #endregion
        #region "将DataReader映射为指定类型集合"
        /// <summary>
        /// 将DataReader映射为指定类型集合
        /// </summary>
        /// <typeparam name="TTarget">目标类型</typeparam>
        /// <param name="reader">DataReader对象</param>
        /// <returns>更新后的目标类型对象集合</returns>
        public IEnumerable<TTarget> DataReaderMapTo<TTarget>(IDataReader reader)
        {
            if (_configuration.FindTypeMapFor<IDataReader, IEnumerable<TTarget>>() != null)
            {
                return _mapper.Map<IDataReader, IEnumerable<TTarget>>(reader);
            }
            var config = new MapperConfiguration(cfg => cfg.CreateMap<IDataReader, IEnumerable<TTarget>>());
            var mapper = config.CreateMapper();
            return mapper.Map<IDataReader, IEnumerable<TTarget>>(reader);

        }
        #endregion

        #endregion

    }
    #endregion

}
